import { useContext } from "react";
import JoinLine from "./JoinLine";
import AssistLine from "./AssistLine";
import BaseNode from "./BaseNode";
import { BaseContext, NodeProp } from "./ContainerProvider";
import { getAnchorPosition } from "./Anchors";

export default function Container() {
  const { state, dispatch, events } = useContext(BaseContext);
  function handleMouseMove(e: React.MouseEvent) {
    if (events.hasEvent("dragStart")) {
      const { offsetX, offsetY, index } = events.trigger("dragStart");
      const newNode = state.nodes[index];
      newNode.position.x = e.clientX - offsetX;
      newNode.position.y = e.clientY - offsetY;
      dispatch({
        type: "nodeChange",
        payload: {
          index,
          newNode,
        },
      });
    }
    if (events.hasEvent("lineStart")) {
      const { x, y } = events.trigger("lineStart");
      const start = { x, y };
      const end = {
        x: e.clientX - (state.containerInfo.x ? state.containerInfo.x : 0),
        y: e.clientY - (state.containerInfo.y ? state.containerInfo.y : 0),
      };
      dispatch({
        type: "drawAssistLine",
        payload: { start, end },
      });
    }
  }

  function nodeAnchorCheck(
    node: NodeProp,
    x: number,
    y: number,
    nodeIndex: number
  ) {
    const { anchor } = node;
    const posInfo = getAnchorPosition(node);
    if (anchor) {
      anchor.forEach((pos) => {
        const { cx, cy } = posInfo[pos];
        if (x >= cx - 5 && x <= cx + 5 && y <= cy + 5 && y >= cy - 5) {
          let startInfo = events.trigger("lineStart");
          if (startInfo) {
            dispatch({
              type: "addJoinLine",
              payload: {
                start: {
                  nodeIndex: startInfo.index,
                  anchorPos: startInfo.position,
                },
                end: {
                  nodeIndex: nodeIndex,
                  anchorPos: pos,
                },
              },
            });
          }
        }
      });
    }
  }

  function handleMouseUp(e: React.MouseEvent) {
    state.nodes.forEach((node, index) => {
      nodeAnchorCheck(
        node,
        e.clientX - (state.containerInfo.x ? state.containerInfo.x : 0),
        e.clientY - (state.containerInfo.y ? state.containerInfo.y : 0),
        index
      );
    });
    dispatch({
      type: "drawAssistLine",
      payload: {},
    });
    events.off("dragStart");
    events.off("lineStart");
  }

  return (
    <svg
      id="mainSVG"
      width={state.containerInfo.width}
      height={state.containerInfo.height}
      style={{ marginTop: 0 }}
      onMouseMove={(e) => {
        handleMouseMove(e);
      }}
      onMouseUp={(e) => {
        handleMouseUp(e);
      }}
      onClick={() =>
        dispatch({
          type: "setCurrent",
          payload: null,
        })
      }
    >
      {state.nodes.map((node, index) => {
        return (
          <BaseNode
            {...node}
            key={index}
            index={index}
            fill={node.fill ? node.fill : "#ffffff"}
            stroke={
              state.currentNode && index === state.currentNode.index
                ? "red"
                : "#333"
            }
          />
        );
      })}
      {state.lines.map((line, index) => {
        return <JoinLine {...line} key={index} />;
      })}
      <AssistLine {...state.assisitLine} />
    </svg>
  );
}
